package com.djakapm.swing.component.tab;

import javax.swing.*;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class TabUI extends BasicTabbedPaneUI {
    private TabUIMouseListener listener;
    private Tab tab;
    private int overTabIndex;
    private Point mousePoint;
    
    public TabUI(Tab tab) {
        super();
        this.tab = tab;
        this.listener = new TabUIMouseListener(tab);
    }

    protected int getOverTabIndex(){
        return this.overTabIndex;
    }
    protected MouseListener createMouseListener() {
        return this.listener;
    }

    protected MouseMotionListener createMouseMotionListener() {
        return this.listener;
    }

    @Override
    public void paint(Graphics g, JComponent c) {
        super.paint(g, c);
    }

    protected int getTabAtLocation(int x, int y) {
        int tabCount = this.tab.getTabCount();
        for (int i = 0; i < tabCount; i++) {
            if(i >= this.rects.length){break;}
            if (this.rects[i].contains(x, y)) {
                return i;
            }
        }
        return -1;
    }

    @Override
    protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rectangles,
                            int tabIndex, Rectangle iconRectangle, Rectangle textRectangle) {
        Rectangle tabRectangle = rectangles[tabIndex];
        super.paintTab(g, tabPlacement, rectangles, tabIndex, iconRectangle, textRectangle);

        if (!this.tab.isClosable()) {
            return;
        }

        int dx = this.calculateCloseIconX(tabRectangle);
        int dy = this.calculateCloseIconY(tabRectangle);

        this.listener.setCloseRegion(dx, dy);

        this.paintCloseIcon(g, dx, dy);
        this.paintHoverCloseIcon(g);

    }

    private int calculateCloseIconX(Rectangle rectangle) {
        return rectangle.x + rectangle.width - 18;
    }

    private int calculateCloseIconY(Rectangle rectangle) {
        return (rectangle.y + rectangle.height) / 2 - 5;
    }

    protected void paintCloseIcon(Graphics g, int dx, int dy) {
        g.setColor(Color.GRAY);
        g.drawLine(dx + 2, dy + 2, dx + 8, dy + 8);
        g.drawLine(dx + 8, dy + 2, dx + 2, dy + 8);
    }

    protected void paintHoverCloseIcon(Graphics g) {
        if (this.overTabIndex > -1 && this.overTabIndex < rects.length) {
            Rectangle hoverTabRectangle = rects[this.overTabIndex];
            int hdx = this.calculateCloseIconX(hoverTabRectangle);
            int hdy = this.calculateCloseIconY(hoverTabRectangle);
            this.listener.setCloseRegion(hdx, hdy);
            if (this.mousePoint != null) {
                boolean inCloseRange = this.listener.getCloseRegion().contains(this.mousePoint);
                if (inCloseRange) {
                    g.drawRect(hdx, hdy, 10, 10);
                    g.setColor(Color.GRAY);
                    g.fillRect(hdx, hdy, 10, 10);
                    g.setColor(Color.WHITE);
                    g.drawLine(hdx + 2, hdy + 2, hdx + 8, hdy + 8);
                    g.drawLine(hdx + 8, hdy + 2, hdx + 2, hdy + 8);
                    this.tab.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                } else {
                    this.tab.setCursor(Cursor.getDefaultCursor());
                }
            }

        }

    }

    @Override
    protected int calculateTabWidth(int tabPlacement, int tabIndex,
                                    FontMetrics metrics) {
        return super.calculateTabWidth(tabPlacement, tabIndex, metrics) + 200;
    }

    @Override
    protected int calculateTabHeight(int tabPlacement, int tabIndex,
                                     int fontHeight) {
        return super.calculateTabHeight(tabPlacement, tabIndex, fontHeight) + 5;
    }


    class TabUIMouseListener extends MouseHandler implements MouseMotionListener {
        private Rectangle closeRectangle;
        private Tab tab;

        public TabUIMouseListener(Tab tab) {
            super();
            this.tab = tab;
        }

        public Rectangle getCloseRegion() {
            return this.closeRectangle;
        }

        public void setCloseRegion(int dx, int dy) {
            this.closeRectangle = new Rectangle(dx, dy, 10, 10);
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            Action afterTabCloseAction;

            super.mouseClicked(e);
            if (!this.tab.isClosable()) {
                return;
            }
            
            int idx = this.tab.getSelectedIndex();
            if(idx == -1){return;}
            if(this.closeRectangle == null){return;}
            
            if (this.closeRectangle.contains(e.getPoint())) {
                if(this.tab.isDefaultCloseOperation()){
                    this.tab.removeTabAt(idx);
                }
                if(this.tab.getAfterTabCloseAction() != null){
                 afterTabCloseAction = this.tab.getAfterTabCloseAction();
                 ActionEvent ae = new ActionEvent(this.tab,ActionEvent.ACTION_PERFORMED,null);
                 afterTabCloseAction.actionPerformed(ae);
                }
            }
        }

        @Override
        public void mousePressed(MouseEvent e) {
            super.mousePressed(e);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            super.mouseReleased(e);
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            super.mouseEntered(e);
        }

        @Override
        public void mouseExited(MouseEvent e) {
            super.mouseExited(e);
        }

        public void mouseDragged(MouseEvent e) {
        }

        public void mouseMoved(MouseEvent e) {
            TabUI.this.mousePoint = e.getPoint();
            this.tab.repaint();
            TabUI.this.overTabIndex = TabUI.this.getTabAtLocation(e.getX(), e.getY());
        }

    }
}
